/*
 * @Author: xiaosihan
 * @Date: 2021-11-28 21:53:33
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2023-12-05 16:46:56
 */

import { Box3, Color, DoubleSide, Matrix4, Mesh, MeshLambertMaterial, MeshPhongMaterial, MeshStandardMaterial, Vector3 } from "three";
import RingBufferGeometry from "./RingBufferGeometry";
import Transition from "./Transition";

export default class RingMesh extends Mesh {

    constructor() {
        super();
        this.geometry = new RingBufferGeometry();
        this._transitionParam.setDuration(5000);
        this._transScale.setDuration(300);
    }

    frustumCulled: boolean = false;

    // 漫反射材质
    material = new MeshStandardMaterial({
        transparent: false,
        opacity: 1,
        side: DoubleSide,
        wireframe: false,
        roughness: 0.5,
        metalness: 0.5
    });

    // 动画参数
    _transitionParam = new Transition({
        height: 0, // 高度
        startAngle: 0,
        angle: 0
    });

    _transScale = new Transition({
        scale: 1
    });

    static ringGeometry = new RingBufferGeometry();

    static tempVector = new Vector3(0, 0, 0);

    // z轴的正方向
    static ZVector3 = new Vector3(0, 0, 1);

    // y轴的正方向
    static YVector3 = new Vector3(0, 1, 0);

    // 相机的投影矩阵
    static viewProjectionMatrix = new Matrix4();

    // 对象的视图矩阵
    static viewMatrix = new Matrix4();

    //3d盒子
    static box3 = new Box3();

    //中心点
    static center = new Vector3();

    // 动画效果是否执行完成
    transitionIsDone(): boolean {
        return this._transitionParam.isDone() && this._transScale.isDone();
    }

    // 鼠标滑动事件
    onMousemove?: (e: MouseEvent) => void;
    // 鼠标离开事件
    onMouseleave?: (e: MouseEvent) => void;
    //鼠标进入事件
    onMouseenter?: (e: MouseEvent) => void;
    //鼠标按下事件
    onMousedown?: (e: MouseEvent) => void;
    //鼠标弹起事件
    onMouseup?: (e: MouseEvent) => void;
    // 点击事件
    onClick?: (e: MouseEvent) => void;
    //鼠标样式 同css的cursor // pointer
    cursor = "pointer"
    //判断是否有鼠标事件 没有鼠标时间的对象不参与拾取计算
    hasMoseEvent() {
        if (this.cursor || this.onClick || this.onMouseup || this.onMousedown || this.onMouseenter || this.onMouseleave || this.onMousemove) {
            return true;
        }
        return false;
    }

    setParam({ startAngle, angle, height, color }: { startAngle: number, angle: number, height: number, color: string }) {
        this._transitionParam.set({ startAngle, angle, height });
        this.material.color = new Color(color);
        this.onBeforeRender = this._onBeforeRender;
    }

    setScale(scale: number = 1) {
        this._transScale.set({ scale });
        this.onBeforeRender = this._onBeforeRender;
    }

    _onBeforeRender = () => {
        if (!this.transitionIsDone()) {

            const startAngle = this._transitionParam.get("startAngle");
            const angle = this._transitionParam.get("angle");
            const height = this._transitionParam.get("height");
            const scale = this._transScale.get("scale");

            const originPosition = RingMesh.ringGeometry.getAttribute("position");
            const position = this.geometry.getAttribute("position");

            for (let i = 0; i < position.count; i++) {
                RingMesh.tempVector.set(
                    originPosition.getX(i),
                    0,
                    originPosition.getZ(i)
                );

                let currentAngle = RingMesh.tempVector.angleTo(RingMesh.ZVector3);

                let nowAngle = ((currentAngle / (Math.PI)) * angle) + startAngle - currentAngle;

                RingMesh.tempVector.applyAxisAngle(RingMesh.YVector3, nowAngle);

                const { x, z } = RingMesh.tempVector;

                position.setX(i, (x * scale) || 0);
                position.setY(i, (originPosition.getY(i) * height) || 0);
                position.setZ(i, (z * scale) || 0);

            }// for
            position.needsUpdate = true;
            this.geometry.computeVertexNormals();
            this.geometry.computeBoundingBox();
            this.geometry.boundingBox!.getCenter(RingMesh.center);
            this.position.copy(RingMesh.center);
            this.geometry.center();

        } else {
            this.onBeforeRender = () => { }
            this.geometry.computeBoundingSphere();
            this.geometry.computeBoundingBox();
        }

    }
}

